package com.moon.admin.tools.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.moon.admin.framework.domain.MoonPage;
import com.moon.admin.framework.springmvc.domain.R;
import com.moon.admin.framework.syslog.annotation.SysLog;
import com.moon.admin.framework.util.MoonException;
import com.moon.admin.framework.util.ToolUtils;
import com.moon.admin.tools.ToolsConstants;
import com.moon.admin.tools.entity.GenTable;
import com.moon.admin.tools.entity.GenTableColumn;
import com.moon.admin.tools.servcie.GenTableColumnService;
import com.moon.admin.tools.servcie.GenTableService;
import com.moon.admin.tools.utils.GenUtils;
import com.moon.admin.tools.utils.VelocityUtils;
import com.moon.admin.tools.domain.TableListQueryVO;

/**
 * 代码生成 操作处理
 * @author ninglong
 */
@RestController
@RequestMapping("/tools/gen")
public class GenController {

    @Autowired
    private GenTableService genTableService;
    @Autowired
    private GenTableColumnService genTableColumnService;

    /**
     * 查询代码生成列表
     */
    @PostMapping("/list")
    public R<MoonPage<GenTable>> genList(@RequestBody TableListQueryVO tableListQueryVO) {
        IPage<GenTable> page = new Page<>(tableListQueryVO.getPage(), tableListQueryVO.getLimit());
        List<GenTable> list = genTableService.selectDbTableList(page, tableListQueryVO);
        page.setRecords(list);
        return R.success(MoonPage.of(page));
    }

    /**
     * 获取表的配置信息
     */
    @GetMapping(value = "/getTableInfo")
    public R<Map<String, Object>> getTableInfo(Integer dataSourceId,String tableName) {
        GenTable table = genTableService.getOne(Wrappers.<GenTable>lambdaQuery().eq(GenTable::getTableName,tableName).eq(GenTable::getDataSourceId,dataSourceId));
        if(table==null){
            IPage<GenTable> page = new Page<>(1, 1);
            TableListQueryVO tableListQueryVO = TableListQueryVO.builder().tableName(tableName).build();
            List<GenTable> list = genTableService.selectDbTableList(page, tableListQueryVO);
            table = ToolUtils.isEmpty(list)?null:list.get(0);
        }
        if(table==null){
            throw new MoonException("表【"+tableName+"】不存在");
        }
        table.setClassName(ToolUtils.convertToCamelCase(table.getTableName()));
        List<GenTableColumn> list = genTableColumnService.selectColumnListByTableIdAndTableName(table.getId(),tableName);
        //没有手动设置则使用默认配置
        list = list.stream().filter(entity->!ToolUtils.contains(ToolsConstants.COLUMN_NAME_DEFAULT, entity.getColumnName())).collect(Collectors.toList());
        list.forEach(entity-> GenUtils.initColumnField(entity));
        Map<String, Object> map = new HashMap<String, Object>(2);
        map.put("info", table);
        map.put("columns", list);
        return R.success(map);
    }

    /**
     * 修改保存代码生成业务
     */
    @SysLog(mod = "代码生成", fun = "修改保存代码")
    @PostMapping("/editSave")
    public R<Void> editSave(@RequestBody GenTable genTable) {
        genTableService.editSave(genTable);
        return R.success();
    }

    /**
     * 预览代码
     */
    @GetMapping("/preview")
    public R<Map<String, String>> preview(Integer dataSourceId,String tableName) throws IOException {
        Map<String, String> dataMap = new LinkedHashMap<>();
        // 查询表信息
        GenTable table = genTableService.getOne(Wrappers.<GenTable>lambdaQuery().eq(GenTable::getTableName,tableName).eq(GenTable::getDataSourceId,dataSourceId));
        if(table==null){
            throw new MoonException("请先配置代码生成信息");
        }
        // 查询列信息
        List<GenTableColumn> columns = genTableColumnService.list(Wrappers.<GenTableColumn>lambdaQuery().eq(GenTableColumn::getTableId,table.getId()));
        table.setColumns(columns);
        VelocityUtils.initVelocity();
        VelocityContext context = VelocityUtils.prepareContext(table);
        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template,"UTF-8");
            tpl.merge(context, sw);
            dataMap.put(template, sw.toString());
        }
        return R.success(dataMap);
    }

    /**
     * 生成代码（下载方式）
     */
    @SysLog(mod = "代码生成", fun = "生成代码（下载方式）")
    @GetMapping("/download")
    public void download(HttpServletResponse response, Integer dataSourceId,String tableName) throws IOException {
        response.reset();
        response.addHeader("Access-Control-Allow-Origin", "*");
        GenTable table = genTableService.getOne(Wrappers.<GenTable>lambdaQuery().eq(GenTable::getTableName,tableName).eq(GenTable::getDataSourceId,dataSourceId));
        if(table==null){
            response.addHeader("Access-Control-Expose-Headers", "error-msg");
            response.addHeader("error-msg", java.net.URLEncoder.encode("请先配置代码生成信息", "UTF-8"));
        }else{
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ZipOutputStream zip = new ZipOutputStream(outputStream);
            genTableService.generatorCode(table.getId(), zip);
            IOUtils.closeQuietly(zip);
            byte [] data = outputStream.toByteArray();
            response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-Disposition", "attachment; filename=moon.zip");
            response.addHeader("Content-Length", "" + data.length);
            response.setContentType("application/octet-stream; charset=UTF-8");
            IOUtils.write(data, response.getOutputStream());
        }
    }
}